package com.paradigmatecnologico;

import java.net.MalformedURLException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.util.SimpleOrderedMap;

public class SearchSolr {

	private static final String url = "http://localhost:8080/solr/mp3";

	public static void main(String[] args) throws MalformedURLException {

		CommonsHttpSolrServer solrServer = new CommonsHttpSolrServer(url);

		// exampleFacets(solrServer);

		// exampleFilterQuery(solrServer);

		// exampleWildCards(solrServer);

		// exampleBoost(solrServer);

		// exampleFuzzy(solrServer);

		// exampleMoreLikeThis(solrServer);

		// exampleSpell(solrServer);

		// exampleHighlight(solrServer);
	}

	/**
	 * Peticion analoga via http
	 * 
	 * http://localhost:8080/solr/mp3//select/?spellcheck=true&q=*:*&spellcheck.q=appl+topby+cony&qt=/spell&spellcheck.collate=true&spellcheck.build=true&version=1
	 * 
	 * @param solrServer
	 * @throws MalformedURLException
	 */
	public static void exampleSpell(CommonsHttpSolrServer solrServer) throws MalformedURLException {
		SolrQuery query = new SolrQuery();

		query.setQuery("*:*");

		// construye el indice de spellchecker, esto solo se tiene que hacer una vez (si no cambia el indice)
		query.add("spellcheck.build", "true");

		// parametro de control para el spellcheck
		query.add("spellcheck", "true");

		// concatenacion de resultados si se les pasa varios
		query.add("spellcheck.collate", "true");

		// query para el spellchecker, si no se especifica, coge la query por defecto
		query.add("spellcheck.q", "appl topby cony");

		// define el request handler que se va a encargar de la query
		query.add("qt", "/spell");

		try {
			printResponse(solrServer.query(query));
		} catch (SolrServerException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * Peticion analoga via http
	 * 
	 * http://localhost:8080/solr/mp3/select/?q=marca:tony~0.7
	 * 
	 * 
	 * @param solrServer
	 * @throws MalformedURLException
	 */
	public static void exampleFuzzy(CommonsHttpSolrServer solrServer) throws MalformedURLException {
		SolrQuery query = new SolrQuery();

		// con '~' se le define el grado de similitud que debe tener para hacer el match
		query.setQuery("marca:tony~0.7");
		try {
			printResponse(solrServer.query(query));
		} catch (SolrServerException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * Peticion analoga via http
	 * 
	 * http://localhost:8080/solr/mp3/select/?mlt.mindf=1&mlt.count=1&mlt.fl=nombre,marca&q=id:2&mlt.mintf=1&mlt=true
	 * 
	 * 
	 * @param solrServer
	 * @throws MalformedURLException
	 */
	public static void exampleMoreLikeThis(CommonsHttpSolrServer solrServer) throws MalformedURLException {
		SolrQuery query = new SolrQuery();

		// nos quedamos solo con un anuncio para comprobar que otros articulos nos recomienda
		query.setQuery("id:2");

		// flag para que devuelva resultados de more like this (mlt)
		query.add("mlt", "true");

		// campos a devolver de los anuncios que se recomienden
		query.add("mlt.fl", "nombre,marca");

		// numero de recomendaciones que debe devolver por resultado devuelto
		query.add("mlt.count", "1");

		// minima frecuencia de documentos que deben tener match para devolver recomendaciones para ese resultado
		query.add("mlt.mindf", "1");
		// minima frecuencia de terminos que deben tener para devolver una recomendacion
		query.add("mlt.mintf", "1");
		try {
			printResponse(solrServer.query(query));
		} catch (SolrServerException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * Peticion analoga via http
	 * 
	 * http://localhost:8080/solr/mp3/select/?q=*:*&fq=enStock:true
	 * 
	 * 
	 * @param solrServer
	 * @throws MalformedURLException
	 */
	public static void exampleFilterQuery(CommonsHttpSolrServer solrServer) throws MalformedURLException {
		SolrQuery query = new SolrQuery();

		// solo se devolveran resultados que esten actualmente en stock. Como este tipo de query (articulos en stock) puede ser muy utilizada se mete en la filter query
		// para que quede cacheado y asi en posterirores busquedas solo tenga conjunto de resultados reduciendo el tiempo por query
		query.setFilterQueries("enStock:true");
		query.setQuery("*:*");
		try {
			printResponse(solrServer.query(query));
		} catch (SolrServerException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * Peticion analoga via http
	 * 
	 * http://localhost:8080/solr/mp3/select/?q=marca:app*
	 * 
	 * 
	 * @param solrServer
	 * @throws MalformedURLException
	 */
	public static void exampleWildCards(CommonsHttpSolrServer solrServer) throws MalformedURLException {
		SolrQuery query = new SolrQuery();

		// devolvera todos los resultados de cualquier marca que empiece por 'app'
		query.setQuery("marca:app*");
		try {
			printResponse(solrServer.query(query));
		} catch (SolrServerException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * Peticion analoga via http
	 * 
	 * http://localhost:8080/solr/mp3/select/?fl=nombre,id,score&q=nombre:ipod^10+OR+nombre:zune
	 * 
	 * 
	 * @param solrServer
	 * @throws MalformedURLException
	 */
	public static void exampleBoost(CommonsHttpSolrServer solrServer) throws MalformedURLException {
		SolrQuery query = new SolrQuery();

		// mediante esta query se puede comprobar que los resultados con el nombre ipod se situaran antes al tener un boost, si se le quita, el resultado de zune iria primero (tiene un score mas alto al calcularse la
		// frecuencia inversa de los terminos ya que hay menos anuncios con zune)
		query.setQuery("nombre:ipod^10 OR nombre:zune");
		query.setFields("nombre", "id", "score");
		try {
			printResponse(solrServer.query(query));
		} catch (SolrServerException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * Peticion analoga via http
	 * 
	 * http://localhost:8080/solr/mp3/select/?facet.date.start=2010-01-31T23:59:59.999Z&facet=true&facet.query=popularidad:[1+TO+5]&facet.query=popularidad:[6+TO+10]&start=0&q=*:*&facet.date=fechaLanzamiento&facet.field=marca
	 * &facet.field=formatoAudio&facet.date.gap=%2B15DAY&wt=javabin&facet.date.end=2010-06-31T23:59:59.999Z&rows=10
	 * 
	 * 
	 * @param solrServer
	 * @throws MalformedURLException
	 */
	public static void exampleFacets(CommonsHttpSolrServer solrServer) throws MalformedURLException {

		SolrQuery query = new SolrQuery();

		// pedimos todos las facetas para los siguientes campos
		query.addFacetField("marca", "formatoAudio");
		// pedimos las facetas para la siguiente query
		query.addFacetQuery("popularidad:[1 TO 5]");
		query.addFacetQuery("popularidad:[6 TO 10]");

		// facetas de fechas

		// comienzo de la fecha de la faceta
		query.add("facet.date.start", "2010-01-31T23:59:59.999Z");
		// campo que debe ser tratado para conseguir los datos de las facetas
		query.add("facet.date", "fechaLanzamiento");
		// fin de la fecha para la faceta
		query.add("facet.date.end", "2010-06-31T23:59:59.999Z");
		// ventana para la agrupacion de las fechas
		query.add("facet.date.gap", "+15DAY");

		// pedimos todos los resultados sobre los que actuaran las facetas
		query.setQuery("*:*");
		query.setRows(10);
		query.setStart(0);

		QueryResponse response = null;
		try {
			response = solrServer.query(query);
			printResponse(response);
		} catch (SolrServerException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 
	 * Peticion analoga via http
	 * 
	 * http://localhost:8080/solr/mp3/select/?hl.fragsize=200&start=0&q=descripcion:apple&hl.fl=descripcion&hl=true&rows=10
	 * 
	 * 
	 * @param solrServer
	 * @throws MalformedURLException
	 */
	public static void exampleHighlight(CommonsHttpSolrServer solrServer) throws MalformedURLException {
		SolrQuery query = new SolrQuery();
		query.addHighlightField("descripcion");
		query.setHighlightFragsize(200);
		query.setQuery("descripcion:apple");
		query.setRows(10);
		query.setStart(0);

		QueryResponse response = null;
		try {
			response = solrServer.query(query);
			printResponse(response);
		} catch (SolrServerException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * Imprime la respuesta.
	 * 
	 * @param response
	 */

	public static void printResponse(QueryResponse response) {

		List<FacetField> facetFields = response.getFacetFields();
		Map<String, Integer> facetQueries = response.getFacetQuery();
		List<FacetField> facetDates = response.getFacetDates();
		SolrDocumentList results = response.getResults();

		System.out.println("Header");
		System.out.println(response.getHeader().toString());
		System.out.println();

		// imprimimos las facetas por campo
		if (facetFields != null && facetFields.size() > 0) {
			System.out.println("Facetas por campo");
			for (FacetField facet : facetFields) {
				System.out.print("\t" + facet.getName() + "  ");
				// for (Count count : facet.getValues())
				System.out.print(facet.getValues().toString());
				System.out.println();
			}
			System.out.println();
		}

		// imprimimos las facetas por fecha
		if (facetFields != null && facetFields.size() > 0) {
			System.out.println("Facetas por fecha");
			for (FacetField facet : facetDates) {
				System.out.print("\t" + facet.getName() + "  ");
				// for (Count count : facet.getValues())
				System.out.print(facet.getValues().toString());
				System.out.println();
			}
			System.out.println();
		}

		// imprimimos las facetas por query
		if (facetQueries != null && facetQueries.size() > 0) {
			System.out.println("Facetas por query");
			for (Entry<String, Integer> facet : facetQueries.entrySet()) {
				System.out.print("\t" + facet.getKey() + " " + facet.getValue());
			}
			System.out.println();
		}
		System.out.println();

		// imprimimos los resultados
		if (results != null && results.size() > 0) {
			System.out.println("Resultados");

			System.out.println();

			for (SolrDocument document : results) {
				System.out.println(" ------------- ");
				for (String fieldName : document.getFieldNames()) {
					System.out.println(fieldName + ": " + document.getFieldValue(fieldName));
				}
				System.out.println();

			}
		}

		Iterator<Entry<String, Object>> it = response.getResponse().iterator();

		while (it.hasNext()) {
			Entry<String, Object> singleResponse = it.next();
			if (singleResponse.getKey().equals("moreLikeThis")) {
				System.out.println("MoreLikeThis ");
				SimpleOrderedMap<String> values = (SimpleOrderedMap<String>) singleResponse.getValue();
				Iterator<Entry<String, String>> valueIt = values.iterator();
				while (valueIt.hasNext()) {
					Entry<String, String> value = valueIt.next();
					System.out.println(value.toString());
				}
				System.out.println("---");
			} else if (singleResponse.getKey().equals("spellcheck")) {
				System.out.println("Spellchek ");
				SimpleOrderedMap<String> values = (SimpleOrderedMap<String>) singleResponse.getValue();
				Iterator<Entry<String, String>> valueIt = values.iterator();
				while (valueIt.hasNext()) {
					Entry<String, String> value = valueIt.next();
					System.out.println(value.toString());
				}
				System.out.println("---");
			} else if (singleResponse.getKey().equals("highlighting")) {
				System.out.println("HighLight ");
				SimpleOrderedMap<String> values = (SimpleOrderedMap<String>) singleResponse.getValue();
				Iterator<Entry<String, String>> valueIt = values.iterator();
				while (valueIt.hasNext()) {
					Entry<String, String> value = valueIt.next();
					System.out.println(value.toString());
				}
				System.out.println("---");
			}

		}

	}
}
